LLVM核心库优化编译器创建的IR，并将其转换为目标代码。这个巨大的任务可以分解成几个单独的步骤，称为Pass。这些Pass需要按照正确的顺序执行，这是Pass管理器的目标。\par

但为什么不硬编码Pass的顺序呢?编译器的用户通常期望编译器提供不同级别的优化。开发人员在开发期间进行优化，喜欢更快的编译速度。最终的应用程序应该尽可能快地运行，编译器应该能够执行复杂的优化，并接受更长的编译时间。不同的优化级别意味着需要执行的优化通过的数量不同。而且，作为编译器作者，您可能希望提供自己的Pass，可以充分展现您对源语言的了解。例如，您可能想用内联IR或(如果可能的话)用该函数的计算结果替换已知的库函数。对于C语言，这样的Pass是LLVM核心库的一部分，但是对于其他语言，您需要单独提供。在介绍自己的Pass时，您可能需要重新排序或添加一些Pass。例如，如果知道Pass的操作使某些IR代码不可访问，那么您应该运行完自己的Pass之后删除Pass。这里，Pass管理器可以帮助您进行管理。\par

Pass通常根据作用范围进行分类:\par

\begin{itemize}
\item Pass函数接受单个函数作为输入，并仅对该函数执行。
\item Pass模块接受整个模块作为输入。这样的Pass在给定的模块上执行，并可用于该模块中的过程内操作。
\item 调用Pass图以自底向上的顺序遍历调用图的函数。
\end{itemize}

除了IR代码之外，Pass还可能消耗、生成或使一些分析结果无效。有很多不同的分析，例如：别名分析或支配树的构造。支配树帮助将不变代码移出循环，因此执行这种转换的Pass只能在创建支配树之后运行。另一个Pass可能执行可能使现有支配树无效的转换。\par

在编译器内部，Pass管理器有以下功能:\par

\begin{itemize}
\item 分析结果由各Pass共享。这需要您指定跟踪哪个Pass需要哪个分析，以及每个分析的状态。其目标是避免不必要的分析重新计算，并尽快释放分析结果所占用的内存。

\item Pass以流水线方式执行，例如：如果需要依次执行几个Pass函数，那么Pass管理器将在第一个函数上运行这些函数中的每个Pass。然后，将在第二个函数上运行所有的Pass函数，以此类推。这里的基本思想是改进缓存行为，因为编译器只对有限的数据集(即一个IR函数)执行转换，然后转向下一个(有限的)数据集。
\end{itemize}

LLVM中有两个Pass管理器: \par

\begin{itemize}
\item 旧(或遗留的)Pass管理器
\item 新Pass管理器
\end{itemize}

未来是属于新的Pass管理器的，但目前过渡尚未完成。许多关键的Pass(例如目标代码生成)还没有迁移到新Pass管理器，因此理解这两个Pass管理器还挺重要的。\par

旧Pass管理器要求Pass从基类继承，例如：Pass函数从llvm::FunctionPass类继承。相比之下，新Pass管理器基于概念的方法，只需要从特殊的llvm::PassInfo<>语言特性(mixin)类继承。旧Pass管理器没有明确表示Pass之间的依赖关系，而新Pass管理器中，依赖关系需要显式编码。新Pass管理器还具有处理分析的不同方法，并允许通过命令行上的文本表示规范优化流水。一些LLVM用户报告说，仅仅从旧Pass管理器切换到新Pass管理器，编译量就减少了10\%，这是使用新Pass管理器非常有力的理由。\par

首先，我们将为新的Pass管理器实现一个Pass，并探索如何将它添加到优化流水中。稍后，我们还将看看如何使用旧Pass管理器。\par

